package indi.zjh.dp.db;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.DocumentException;

import indi.zjh.dp.orm.Business;
import indi.zjh.dp.orm.BusinessMapDataStrategy;
import indi.zjh.dp.orm.RelationClass;
import indi.zjh.dp.vc.VersionControl;

public class TableRepository {
	private static TableRepository instance = null;
	// 表名 -> 表
	//private Map<RelationClass, Table> allTables;
	
	// 类 -> sql
	private HashMap<RelationClass, String> createSqlm;
	private HashMap<RelationClass, String> insertSqlm;
	private HashMap<RelationClass, String> deleteSqlm;
	private HashMap<RelationClass, String> updateSqlm;
	private HashMap<RelationClass, String> selectSqlm;
	private HashMap<RelationClass, String> selectExSqlm;
	
	// 类名-> sql
	private HashMap<String, String> createSqlc;
	private HashMap<String, String> insertSqlc;
	private HashMap<String, String> deleteSqlc;
	private HashMap<String, String> updateSqlc;
	private HashMap<String, String> selectSqlc;
	private HashMap<String, String> selectExSqlc;
	
	// 类名 -> List<Field>
	private HashMap<String, ArrayList<Field>> objFields;
	// 类名 -> {字段名 -> Field}
	private HashMap<String, HashMap<String, Field>> objFields2;
	
	// A类名_B类名 -> 关系表
	private HashMap<String, String> relationTablem;
	
	private TableRepository()
	{
		//this.allTables = new HashMap<RelationClass, Table>();
		this.createSqlm = new HashMap<RelationClass, String>();
		this.insertSqlm = new HashMap<RelationClass, String>();
		this.deleteSqlm = new HashMap<RelationClass, String>();
		this.updateSqlm = new HashMap<RelationClass, String>();
		this.selectSqlm = new HashMap<RelationClass, String>();
		this.selectExSqlm = new HashMap<RelationClass, String>();
		
		
		this.createSqlc = new HashMap<String, String>();
		this.insertSqlc = new HashMap<String, String>();
		this.deleteSqlc = new HashMap<String, String>();
		this.updateSqlc = new HashMap<String, String>();
		this.selectSqlc = new HashMap<String, String>();
		this.selectExSqlc = new HashMap<String, String>();
		
		this.objFields = new HashMap<String, ArrayList<Field>>();
		
		this.relationTablem = new HashMap<String, String>();
		this.objFields2 = new HashMap<String, HashMap<String, Field>>();
	}
	
	public static TableRepository getInstance()
	{
		if(instance == null)
		{
			instance = new TableRepository();
		}
		return instance;
	}
	
	public String getCreateSql(String clsname)
	{
		return this.createSqlc.get(clsname);
	}
	
	public String getInsertSql(String clsname)
	{
		return this.insertSqlc.get(clsname);
	}
	
	public String getDeleteSql(String clsname)
	{
		return this.deleteSqlc.get(clsname);
	}
	
	public String getUpdateSql(String clsname)
	{
		return this.updateSqlc.get(clsname);
	}

	public String getSelectSql(String clsname)
	{
		return this.selectSqlc.get(clsname);
	}
	
	public String getSelectExSql(String clsname)
	{
		return this.selectExSqlc.get(clsname);
	}

	
	
	public String getCreateSql(RelationClass rc)
	{
		return this.createSqlm.get(rc);
	}
	
	public String getInsertSql(RelationClass rc)
	{
		return this.insertSqlm.get(rc);
	}
	
	public String getDeleteSql(RelationClass rc)
	{
		return this.deleteSqlm.get(rc);
	}
	
	public String getUpdateSql(RelationClass rc)
	{
		return this.updateSqlm.get(rc);
	}
	
	public String getSelectSql(RelationClass rc)
	{
		return this.selectSqlm.get(rc);
	}
	
	public String getSelectExSql(RelationClass rc)
	{
		return this.selectExSqlm.get(rc);
	}
	
	public ArrayList<Field> getFields(RelationClass rc)
	{
		return this.objFields.get(rc.getName());
	}
	
	public ArrayList<Field> getFields(String clsname)
	{
		return this.objFields.get(clsname);
	}

	private void loadClass(RelationClass rc) throws DocumentException, Exception
	{		
		String clsname = rc.getName();
		List<TField> tFields = this.getDataField(rc);
		

		Iterator<TField> iter = tFields.iterator();
		ArrayList<Field> fields = new ArrayList<Field>();
		while(iter.hasNext())
		{
			TField tf = iter.next();
			tf.field.setAccessible(true);
			fields.add(tf.field);
			
			if(!this.objFields2.containsKey(clsname))
			{
				this.objFields2.put(clsname, new HashMap<String, Field>());
			}
			HashMap<String, Field> classFieldMap = this.objFields2.get(clsname);
			classFieldMap.put(tf.field.getName(), tf.field);
		}
		this.objFields.put(clsname, fields);
		
		String tableName = BusinessMapDataStrategy.getTableName(rc);
		Table t = new Table(tableName);
		t.setIgnore(true);
		t.addField(tFields);
		//t.sortFields();
		
		// create sql
		String sql = t.getCreateSql();
		this.createSqlc.put(rc.getName(), sql);
		this.createSqlm.put(rc, sql);

		// insert sql
		sql = t.getInsertSql();
		this.insertSqlc.put(rc.getName(), sql);
		this.insertSqlm.put(rc, sql);
		
		// delete sql
		sql = t.getUpdateSql();
		this.deleteSqlc.put(rc.getName(), sql);
		this.deleteSqlm.put(rc, sql);
				
		// update sql
		sql = t.getUpdateSql();
		this.updateSqlc.put(rc.getName(), sql);
		this.updateSqlm.put(rc, sql);
		
		// select sql
		sql = t.getSelectSql();
		this.selectSqlc.put(rc.getName(), sql);
		this.selectSqlm.put(rc, sql);

		// selectEx sql
		List<TField> texFields = this.getDataFieldEx(rc);
		Table tex = new Table(tableName);
		tex.addField(texFields);
		sql = tex.getSelectSql();
		this.selectExSqlc.put(rc.getName(), sql);
		this.selectExSqlm.put(rc, sql);
	}
	
	public String getRelationInsertSql(String clsnameA, String clsnameB)
	{
		String key = clsnameA + "_" + clsnameB;
		if(!this.relationTablem.containsKey(key))
		{
			this.relationTablem.put(key, key.replace(".", "_").toLowerCase());
		}
		
		String tableName = this.relationTablem.get(key);
		
		return "INSERT INTO `"+tableName+"` VALUES(NULL, ?, ?, ?)";
	}
	
	public String getRelationDeleteSql(String clsnameA, String clsnameB)
	{
		String key = clsnameA + "_" + clsnameB;
		if(!this.relationTablem.containsKey(key))
		{
			this.relationTablem.put(key, key.replace(".", "_").toLowerCase());
		}
		
		String tableName = this.relationTablem.get(key);
		
		return "DELETE FROM `"+tableName+"` WHERE `_t` = ? AND `aid` = ? AND `bid` = ?";
	}
	
	public String getRelationSelectSql(String clsnameA, String clsnameB)
	{
		String key = clsnameA + "_" + clsnameB;
		if(!this.relationTablem.containsKey(key))
		{
			this.relationTablem.put(key, key.replace(".", "_").toLowerCase());
		}
		
		String tableName = this.relationTablem.get(key);
		String tableNameB = this.getTableName(clsnameB);
		
		return "SELECT `"+tableName+"`.`bid` FROM `"+tableName+"` LEFT JOIN `"+tableNameB+"` ON `"+tableName+"`.`bid` = `"+tableNameB+"`.`_id` WHERE `"+tableName+"`.`_t` = ? AND `"+tableName+"`.`aid` = ? AND `"+tableNameB+"`.`_deleted` = 0";
	}
	
	public String getTableName(String clsname)
	{
		return clsname.replace(".", "_").toLowerCase();
	}
	
	public Field getFieldByName(String clsname, String fieldname)
	{
		if(!this.objFields2.containsKey(clsname))
			return null;
		HashMap<String, Field> classFieldMap = this.objFields2.get(clsname);
		if(!classFieldMap.containsKey(fieldname))
			return null;
		return classFieldMap.get(fieldname);
	}

	public List<TField> getDataField(RelationClass rc) throws DocumentException, Exception
	{
		List<TField> ret = new ArrayList<TField>();
		Class<?> baseClass = Business.class;
		Field[] fields = baseClass.getDeclaredFields();
		for(int i = 0; i < fields.length; ++i)
		{
			if(fields[i].getName().startsWith("_"))
			{
				TField tf = BusinessMapDataStrategy.getDataField(fields[i]);
				ret.add(tf);
			}
		}
		
		List<Field> baseFields = rc.getBasicFields();
		Iterator<Field> iter = baseFields.iterator();
		while(iter.hasNext())
		{
			Field field = iter.next();

			if(field.getName().startsWith("_"))
				continue;

			if((field.getModifiers() & Modifier.STATIC) == 0)
			{
				TField tf = BusinessMapDataStrategy.getDataField(field);
				ret.add(tf);
			}
		}
		
		Collections.sort(ret, new Comparator<TField>() {
			@Override
			public int compare(TField o1, TField o2) {
				// TODO Auto-generated method stub
				return o1.name.compareTo(o2.name);
			}
		});
		
		return ret;
	}
	
	public List<TField> getDataFieldEx(RelationClass rc) throws DocumentException, Exception
	{
		HashSet<String> needField = new HashSet<String>();
		needField.add("_id");
		needField.add("_v");
		
		List<TField> ret = new ArrayList<TField>();
		Class<?> baseClass = Business.class;
		Field[] fields = baseClass.getDeclaredFields();
		for(int i = 0; i < fields.length; ++i)
		{
			if(fields[i].getName().startsWith("_") && needField.contains(fields[i].getName()))
			{
//				if(fields[i].getName().startsWith("_"))
//					continue;
				if((fields[i].getModifiers() & Modifier.STATIC) == 0)
				{
					TField tf = BusinessMapDataStrategy.getDataField(fields[i]);
					ret.add(tf);
				}
			}
		}
		
		List<Field> baseFields = rc.getBasicFields();
		Iterator<Field> iter = baseFields.iterator();
		while(iter.hasNext())
		{
			Field field = iter.next();
			if(field.getName().startsWith("_"))
				continue;

			if((field.getModifiers() & Modifier.STATIC) == 0)
			{
				TField tf = BusinessMapDataStrategy.getDataField(field);
				ret.add(tf);
			}
		}
		
		Collections.sort(ret, new Comparator<TField>() {
			@Override
			public int compare(TField o1, TField o2) {
				// TODO Auto-generated method stub
				return o1.name.compareTo(o2.name);
			}
		});
		
		return ret;
	}
}
